package com.michaelbulava.TFS.vcs.internal.providers;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.*;
import com.intellij.openapi.vfs.VirtualFile;
import com.michaelbulava.TFS.Messages;
import com.michaelbulava.TFS.log.FileLogger;
import com.michaelbulava.TFS.vcs.TFSVcs;
import com.michaelbulava.TFS.vcs.exceptions.NotConnectedToTFS;
import com.michaelbulava.TFS.vcs.exceptions.TFSException;
import com.michaelbulava.TFS.vcs.internal.*;
import com.michaelbulava.TFS.vcs.utils.TFSProgressUtil;
import com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Workspace;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by mbulava on 5/7/2015.
 */
public class TFSChangeProvider implements ChangeProvider {
    private static final Logger log = FileLogger.getInstance(TFSChangeProvider.class);
    private final Project myProject;

    public TFSChangeProvider(Project project){
        this.myProject = project;
    }

    /**
     * <p>Get changes from point of view of VCS. The vcs plugin should invoke methods on the {@code builder} object to
     * report how changes in dirtyScope map to VCS.</p>
     * <p/>
     * <p>The implementations of this method should not report changes outside of the dirty scope, but if these changes
     * are reported, they will be ignored by the caller.</p>
     *
     * @param dirtyScope a changes on the virtual file system
     * @param builder    a builder of VCS changes
     * @param progress   a current progress object
     * @param addGate
     * @throws VcsException if there there is a VCS specific problem
     */
    @Override
    public void getChanges(VcsDirtyScope dirtyScope, final ChangelistBuilder builder, final ProgressIndicator progress,
                           final ChangeListManagerGate addGate) throws VcsException {

        if (this.myProject.isDisposed()) {
            return;
        }
        if (builder == null) {
            return;
        }
        progress.setText("Processing changes");
        RootsCollection.FilePathRootsCollection roots = new RootsCollection.FilePathRootsCollection();
        roots.addAll(dirtyScope.getRecursivelyDirtyDirectories());

        ChangeListManager changeListManager = ChangeListManager.getInstance(this.myProject);
        for (FilePath dirtyFile : dirtyScope.getDirtyFiles()) {
            if ((dirtyFile.getVirtualFile() == null) ||
                    !TFSVcs.isIgnored(myProject, dirtyFile)
                /*(!changeListManager.isIgnoredFile(dirtyFile.getVirtualFile()))*/) {
                roots.add(dirtyFile);
            }
        }
        if (roots.isEmpty()) {
            return;
        }

        try {
            final Ref<Boolean> mappingFound = Ref.create(Boolean.valueOf(false));

            WorkstationHelper.processByWorkspaces(roots, true, myProject, progress,
                    new WorkstationHelper.VoidDelegateProcess() {
                        @Override
                        public void executeRequest(Workspace workspace, List<FilePath> localPaths) throws TFSException {
                            TFSProgressUtil.setProgressText2(progress, Messages.getString("TFSChangeProvider.UpdatingFileStatus"));

                            StatusProvider.visitByStatus_V2(workspace, localPaths, true, progress,
                                    myProject, addGate,
                                    new ChangelistBuilderStatusVisitor(myProject, builder, workspace));
                                    //new ChangelistBuilderStatusVisitor(myProject, builder, workspace), myProject);

                            mappingFound.set(Boolean.valueOf(true));
                        }
                    });
        } catch(NotConnectedToTFS e){
            List<FilePath> files = new ArrayList<>();
            files.addAll(roots);
            TFSProgressUtil.setProgressText2(progress, Messages.getString("TFSChangeProvider.UpdatingFileStatus"));

//            StatusProvider.visitDisconnectedStatus(files, true, progress, myProject,
//                    new DisconnectedChangelistBuilderStatusVisitor(myProject, builder));
        } catch (TFSException e) {
            throw new VcsException(e);
        }
    }

    /**
     * Returns true if the initial unsaved modification of a document should cause dirty scope invalidation for the file
     * corresponding to the document.
     *
     * @return true if document modification should mark the scope as dirty, false otherwise
     */
    @Override
    public boolean isModifiedDocumentTrackingRequired() {
        return true;
    }

    /**
     * performs working copy "cleanup"
     *
     * @param files - locked directories
     */
    @Override
    public void doCleanup(List<VirtualFile> files) {

    }
}
